//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "gtag.h"
#include <aura.h>

DLinkNode CGhostTag::s_hashList[GHOST_HS_SLOTS];
PVoid     CGhostTag::s_hHashLock = NULL;

ECode CGhostTag::S_Initialize()
{
    ECode ec = NOERROR;

    ec = AuraCriticalSection_Create(&s_hHashLock);
    if (FAILED(ec)) {
        return ec;
    }

    for (Int32 i = 0; i < GHOST_HS_SLOTS; i++) {
        s_hashList[i].Initialize();
    }

    return NOERROR;
}

void CGhostTag::S_Destroy()
{
    if (NULL != s_hHashLock) {
        AuraCriticalSection_Destroy(s_hHashLock);
        s_hHashLock = NULL;
    }

    return ;
}

ECode CGhostTag::S_Create(
            /* [in] */ ProcessId processId,
            /* [in] */ LabelType labelType,
            /* [out] */ CGhostTag ** ppLabel)
{
    CGhostTag * pTag = NULL;

    assert(NULL != ppLabel);
    pTag = new CGhostTag(processId, labelType, NULL);
    if (NULL == pTag) {
        return E_OUT_OF_MEMORY;
    }
    *ppLabel = pTag;

    return NOERROR;
}

void CGhostTag::S_Delete(
        /* [in] */ CGhostTag * pTag)
{
    assert(NULL != pTag);
    delete pTag;

    return ;
}

void CGhostTag::S_Attach(
        /* [in] */ CGhostTag * pTag,
        /* [in] */ Ghost * pGhost)
{
    pTag->m_pGhost = pGhost;
    Lock(s_hHashLock);
    s_hashList[GHOST_HASHCODE(pTag->m_processId)].InsertLast(pTag);
    Unlock(s_hHashLock);

    return ;
}

ECode CGhostTag::S_Create(
        /* [in] */ ProcessId processId,
        /* [in] */ LabelType labelType,
        /* [in] */ Ghost * pGhost)
{
    CGhostTag * pTag = NULL;

    pTag = new CGhostTag(processId, labelType, pGhost);
    if (NULL == pGhost) {
        return E_OUT_OF_MEMORY;
    }
    Lock(s_hHashLock);
    s_hashList[GHOST_HASHCODE(processId)].InsertLast(pTag);
    Unlock(s_hHashLock);

    return NOERROR;
}

ECode CGhostTag::S_Delete(
        /* [in] */ ProcessId processId,
        /* [in] */ Ghost * pGhost)
{
    CGhostTag * pTag = NULL;
    DLinkNode * pHead = NULL;

    pHead = &s_hashList[GHOST_HASHCODE(processId)];
    Lock(s_hHashLock);
    S_Dump();

    ForEachDLinkNode(CGhostTag*, pTag, pHead)
    {
        if ((processId == pTag->m_processId)
            && (pGhost == pTag->m_pGhost)) {
            pTag->Detach();
            Unlock(s_hHashLock);
            delete pTag;
            return NOERROR;
        }
    }
    Unlock(s_hHashLock);
    return E_DOES_NOT_EXIST;
}


#ifdef _GHOSTTAG_DEBUG
void CGhostTag::S_Dump()
{
    CGhostTag * pTag   = NULL;
    DLinkNode * pHead = NULL;
    Int32 num = 0;

    Aura_printf("\n");
    for (Int32 i =0; i < GHOST_HS_SLOTS; i++) {
        pHead = &s_hashList[i];
        ForEachDLinkNode(CGhostTag*, pTag, pHead)
        {
            Aura_printf(" <Label %d> :process (%d), pGhost(0x%x).\n",
                        num, pTag->m_processId, pTag->m_pGhost);
            num++;
        }
    }
    Aura_printf("\n");
    return ;
}
#endif

ECode CGhostTag::S_Delete(
        /* [in] */ ProcessId processId)
{
    CGhostTag * pTag = NULL;
    DLinkNode * pNode = NULL;
    DLinkNode * pHead = NULL;

    Lock(s_hHashLock);
    S_Dump();

    pHead = &s_hashList[GHOST_HASHCODE(processId)];
    pNode = pHead->Next();
    while(pNode != pHead) {
        pTag = (CGhostTag *)pNode;
        pNode = pNode->Next();
        if (processId == pTag->m_processId) {
            pTag->Detach();
            pTag->DoAtException();

            delete pTag;
        }
    }
    Unlock(s_hHashLock);

    return NOERROR;
}

